对于多数初学者来说,C++ 的难度并不在语法语意等语言层面,而是没学过 C++ 所支持的面向对象、泛型编程、元编程、函数式编程等不同编程范式,以至于标准模板库(STL)里关于数据结构和算法的知识,甚至一些部分与计算机架构、编译原理、操作系统等知识相关。学习 C++ 可以同时学习、实践这些相关知识。
按面试经验,本科同学们的 C++ 水平真是天差地別的。你能学到什么程度,就看你的努力程度了。
1个月: 都说C++难,但聪明如我,一个月就读完了C++ primer,我看这C++也不过如此.
3个月: 原来之前一直在用C++语法写C... 开始正式学习C++...
1年: 今天花一下午一定要琢磨明白这段代码啥意思...
2年: C++太他妈难了, 发明C++的可以吃X去了
3年: 这辈子绝对不能继续搞C++了,珍惜生命,远离C++
4年: ......
5年: 终于神功初成, 大家好,我是C++专家,疑难杂症请问我
7年: 我比较擅长XXX这块,其他方面我是外行
10年: 我有一定的C++基础...
由于现在懂C++的人少,很多人对C++有点望而生畏,这种误解需要纠正一下。
(补充:C++在很多重要领域都是不可替代的,“有用还是没用”的问题根本不需要考虑。)
1、虽然C++的上限非常高,但是分阶段性逐步学习是没有问题的。
按照流行的说法,C++集成了多种编程范式,包括过程式编程、面向对象、泛型、函数式等等(我总感觉实际不止4种)。
而且,根据软件的原理来说,只需要一种编程范式(比如过程式),就已经可以解决所有问题了,从数学上来讲这么多的范式并不是必要的。实际上,只要你掌握了基础的过程式编程,再加一半面向对象的技术,就已经可以解决相当多问题了。
比如很早以前MFC还流行的时候,大部分人用的C++也只不过就是OO那些东西而已,照样做出了丰富多彩的应用程序。
2、如何分阶段学习
进行长期的C++学习,很像是攀岩,虽然看似学习曲线陡峭,但是每一步都是有根有据的,并不会一下子飞起来。
1、学习C++并不需要从C开始,但是指针、函数等等基本的使用务必做到100%熟悉。这也是学习C语言最强调的一点。C++对类型的限定更为严格,相对C来说反而不会很“跳脱”,可能反而好学一些。
2、之后就是class相关的一部分,广泛来说就是OO那一套东西。基本的有类、对象,到最后不过也就是多态而已。这一部分还是没什么太难的东西,多思考、多实践即可。
3、再往后遇到模版、泛型。虽然泛型编程这部分上限很高,但是下限也很低。你只要能正确地利用泛型扩展class的功能、提高易用性,就算是懂了一半;而且这一半一点也不难,照猫画虎即可学会。
4、到这里同时还会遇到STL和常用容器,往浅说,你只要知道什么时候用什么容器、怎样用好容器;往深说,你要尽可能多了解多种容器的实现原理、内存布局和规则等等。一步一步深入理解。
5、这时候你就已经来到一个“初级C++程序员”的台阶上了,再往后最好不要闭门造车,还是要兼顾学习和项目实践,才能更稳定地进一步发展,避免走歪。
可能遇到的麻烦
只要一步一步来,一年左右时间应该能基本达到上面所说的水准,但在这个过程中可能遇到一些比较大的坎,比如:
知道“宏”怎么用,但是复杂的看不懂。
知道面向对象怎么写,但是不能合理设计、使用OO
指针、引用、对象、const、运算符重载都懂,但是放在一起就乱了。
写出来的程序内存管理比较乱,有崩溃或者泄露不知道怎么改。
等等这些问题都是会发生的,要解决这些问题只要记住一点——不要在意学习快慢,在细节上花10倍时间是值得的,只要每个地方都花时间搞懂,那就离大牛不远了。你在知乎上看到的很多C++大牛,都是在这方面有意无意地花费了海量的时间,自然就成为高手了。
C++虽然上限很高,但是并没有多么可怕,初级有初级的玩法、高级有高级的玩法。只要一步一步做下去,边学习边使用并不会觉得很难。
对于大学生,只要合理投入时间,就一定能达到一个合格的程序员水准。具体有多高水平,一是看你的努力程度,二是看有没有抓住机会多实践(比如毕设、大作业、教研项目等等都是机遇)。
现在积累的越多,在未来就越有不可逾越的壁垒,加油。
首先,你想靠c++来混饭吃,这个想法很有前途。我是大学快毕业的时候才学c++,毕业的时候找的一个码农的工作但是用的不是c++,于是就一边工作一边学习c++。我的性格比较怀旧,一旦学了什么,就想用一辈子,我当年就觉得,如果有什么语言可以混饭吃混一辈子,那只能是c++。
现在的工作已经用了十年c++了,十几年前买的《c++标准程序库》现在已经已经升级到第二版,从c++98变成了c++11。我相信,再过十年,只要我还在做码农的工作,c++还是能够养活我。(下图四本书,购买时间分别为:2017、2004、2003、2016)。
学c++的过程就如同在是爬一座高高的大山,是一个漫长的过程,不仅仅是找工作前要学,工作过程中还是要不断地学习,需要兴趣、耐心。你现在大三,为了找工作,不仅仅是需要学习基本的c++/stl,还要学习一些其它的知识,比如说网络、算法、操作系统、数据库,每样都要知道一些。
cpp里最简单的部分就是c with class,先学到这种程度,你就能处理大部分需求了。真的很大的程序,比如linux内核,mysql, pg, gcc,基本都是这么写的,所谓c语言不能写大型软件完全是谣言。真的写一辈子c with class你也能在另一个世界里找到秩序。干什么干久了都能屌的一逼的。
好多人一开始看就是cpp primer啥的,一棍子打蒙,回答了这个问题的大部分人都是有cpp知识死角的,无死角的几乎没有。然后写比较复杂的项目的时候再去看看虚函数和多态,想想怎样使用设计模式剥离机制和策略。这个就是oox啦。用cpp实践oox。这个是现代大型软件开发的经典套路了。
然后还有啥,写通用库,模版元编程啦。这个需要很长时间训练和思考。
函数式,cpp这些方面还在路上,函数式本身是个超级大坑。
所以我建议不要一下子学习那么多,你可以根据自己的工作环境,先学一个方面,深入了,再慢慢丰满羽翼,一下子把cpp primer搞一遍是有点残酷的。如果要读书,cpp primer案头书。cpp编程思想和cpp语言的设计与演化可以看看。其它可以wiki。
我觉得cpp编程范式太多了,相当于在学好几门语言,所以每个方面都很水很正常了。可以先集中一种范式忽略其它工作。慢慢需要时再逐渐训练和充实自己。
先把C语言搞扎实(这会逼着你把很多基本的计算机问题弄清楚),再学C++,每学一个语法点都要想清楚他为什么这样设计和实现,如果自己用C语言去实现应该会用什么样的方法来实现,如果汇编学的好还可以去阅读反汇编的结果来看看编译器到底是怎么实现的(当然有反编译器来辅助阅读也不错)。
当你学会自己用C或者汇编来实现虚函数,成员函数指针这些的时候,,,C++的二进制上的常用设计手段和设计准则对你没有太多秘密了,只剩文法上的各种新标准新语法了。基本上你应该要能做到看到这些新语法,都能知道他背后的二进制秘密。所以基本不会怕新标准中的改革了。
说说我眼中的c++11后的一些新语法的创新点
显式的右值语义:文法创新
(栈上)变长数组:二进制创新,c++14赶紧又把它给废了(感谢评论指正,c++11就没采纳)。
变长模版参数:文法创新
lambda: 文法创新,帮你自动生成函数对象和捕获变量的构造函数。
c++20的协程(ts):二进制创新,c++唯二提供编译器自动堆上分配内存保存数据的语法糖(第一个是异常)。
在理解好这些c++ 二进制密码之后,对于如何实践C++,避免最容易出问题的内存分配&访问&回收问题,不会有特别大的困难了。但是有一些很成熟的内存使用高阶范式还是值得单独去学习和理解的。例如std::shared_ptr很好用,但是哪些时候类一开始定义时就应该选择使用侵入式引用计数或者std::enable_shared_from_this呢(个人认为是那些可能会在成员函数里自己删除自己且成员函数在设计中是通过间接隐式调用的对象)?
C++之难不在于其语法的复杂性,也不在于二进制层面上语义的杂乱无章,更不在于玄妙得不食人间烟火的模板推导(模板元编程),这些都只是表象。本质上讲,C++跟任何语言比,它很独特很怪异(废话,任何一种语言那个不特异)。
很多时候,C++给人的感觉就是,好像任何一种语言的特性(这话有点夸张),都可以在C++王国中,通过令人发指的奇技淫巧,罄竹难书的花样作死,最后终于可以在一定程度上模拟出来,但是模拟后的结果,又总是存在这样那样的不足,要么因为内存管理,要么因为反射的原因,总之,就是好像可以做一切事情,但最后终于做得不好。这个时候,猿猴要么就直接扑上原生带有这种特性的语言,要么干脆就完全舍弃,放弃治疗,啥技巧也不用,返璞归真,就老老实实一行代码一行代码、不厌其烦、不畏枯燥地一再写地重复类似的功能。而C++自身的优秀特性(析构函数、内存管理、模板、多继承等等),没有任何一种语言整的出来,当然,也可以说,这些玩意都是为了解决C++自身制造出来麻烦,other语言s完全不care这些杂碎。难道,这些好东西就没有一丁点价值了。
更令人难堪的是,迄今为止,C++业界就没有出现过方方面面都让人满意的基础库,也即是性能(对c++猿来说,性能最重要)、可扩展性、易用性、安全性都经得起推敲。所有的通用库、流行库都存在这样那样的诟病,stl如是,boost如是,qt如是,……。所以,就开始有人(现在是普遍都持这种观点啦,十几年前还只是开始)怀疑了,为什么其他语言出来不久,就马上配套相应的官方基础权威平台框架库,就算是C语言,也有标准头文件库,里面也确实没有可争议之处。就C++诸多借口,迟迟交不出答卷。这一定是语言的问题,毫无疑问。就算不是语言的问题,你看看,几十年下来,多少大牛,就搞不出来的东西,由此可见,C++有多麻烦,有多复杂,平常人hold得住吗?
可是,基于C语言,C++多出来任何特性,都确确实实很有价值,用得好,的而且确,可以节省很多很多重复代码。就算最让人诟病的隐式类型转换,虽然一不小心,就给猿猴惊喜,带来理解上麻烦。但是,在可控的情况下,真的可以少写烦心的代码,某些场合,也是奇技淫巧的用武之地。好吧,既然low C都能写出来基础通用库,反而高大上的C++就举步维艰了。问题是,精致的C代码,到了C++舞台上,马上就备受一连串很有道理的指责,类型不安全啦,缺乏弹性啦,不够易用性,甚至连性能(明明在C那里就是极限了),也可以榨出汁来。既然你大C++这么厉害,你行你上啊,少在这里瞎逼逼。几十年了,你换了多少次新马甲,依然虚有其表,金玉其外。可以想象大C++的老脸有多红啊。
所以说,这个世界的猿猴语言分为两大类,C++与其他语言。其他语言稍微努力就能做出来很有群众基础的通用库(不接受也不行,压根就不让你做文章,就不给你后门更好地实现),进而跑步进入共产主义,人生苦短。而C++看着其他语言的通用库,就会瞎逼逼,指指点点,这里不好,那里不对,但是自己无论如何,就是只能做出来小团体运用,自我陶醉的通用库,这些所谓的通用库,最后多半要被历史潮流所淘汰。
当你废了九牛二虎之力搞清楚了C++的对象模型(继承、多继承、虚继承、异常、……),各种数据类型在内存中表示,还搞清楚不同编译器的不同处理方式;兴致勃勃搞起模板元编程从入门到放弃;预处理的伪图灵完备也玩出翔来;将mfc操得体无完肤;对stl、boost也深挖祖坟以至深感失望(stl还好,boost真心烂);C++编译器也被操得死去活来;……,这都有多少年过去了,依然感觉写不好C++代码,依然充满疑惑,代码写来写去,总是感觉写的不对,似乎还可以提升,还可以提升,可以在牺牲性能、类型安全、弹性、易用性的前提下继续加强性能、类型安全、弹性、易用性,你不知道C++的上限在哪里。直到有一天,那一刻,终于到达彼岸。
对于普通用户来说,C++最大的问题,就是缺乏一个高水准高质量的基础通用库,这个库,首先要坚持住零惩罚抽象的底线,不管怎么样,都不得妥协,历史的经验证明,在这一点上退缩的基础库,最后都将导致整个设计框架上的冗余,倒不仅仅只是因为性能的原因。其次,在性能、弹性、使用接口、类型安全等综合方面都要取到很好的平衡点,也就是说用这个库说人话的时候,其性能一定要不差,好用,有弹性,类型上用得不对,编译器就不满意。但是这个基础库又要像大C++语言本身一样,充满后门,只要愿意,随时都可以为了提升某一要素,可以牺牲任何其他要素(比如说为了性能,将使用接口、弹性上搞得很难看)。具体展开来说,这个基础库包括,完备的内存管理(支持一定程度的gc效果,其实就是多次分配,一次统一释放);完备的运行时类型信息;极大地挖掘template的潜力;编译期与运行期的无缝对接,二进制语义上的清晰。至于再具体来说,比如字符串设计,格式化,序列化,IO,侵入式的容器,迭代器,协程等,就是细微末节了。
显然,以上述的要求来评判stl,显然stl很不行的,虽然勉勉强强坚持住零惩罚的底线,但是总体来说,其性能、弹性、使用接口、类型安全的总体分数上是相当低的。1、竟然脑洞大开,将内存管理当做是容器的类型参数来操作,这样玩的严重可怕后果,就不说stl的东西不能很好地用于动态库,想要做有gc效果的内存管理也不好办了;2、对模板的使用只停留在很低的层次上,本来可以提供更多更有力的抽象机制,比如非侵入式接口,比如消息,比如异构容器;3、回避虚函数,回避反射,导致stl的运行时类型信息很薄弱,进而导致垃圾的io stream实现,对面向对象的支持极差,也导致痛苦漫长的编译过程;4、对于编译期的丰富类型信息,只会用类型拭擦一招带到运行期,导致到运行期时丢失了很多重要的信息;5、对于容器的二进制布局,回避,不花心思,所以二进制的复用效果很差;……,算了,对stl的不满,简直是说三天三夜也说不完。所以,以stl为基础来写代码,能不一再反复造轮子,写代码能愉快?
所以,C++的难,说到底,只是通用基础库的实现之难。C++的难,是C++专家的难题,并非普通用户的麻烦。那么,实现通用基础库的难度有多大,从C++面试至今三十多年,还没出现过,你说会有多难呢?那么,为什么会这么难呢?
一直以来,C++专家对C++的认识,一直停留在很低的层面上。面对着C++复杂庞大的类型系统,完全开放式的内存管理,直接操作机器的种种方便,威力无比的template,很丑陋又好像很重要很有作用的预处理,厚颜无耻的多继承以及不定时炸弹的异常,这些东西造就了C++无限可能的同时,也造成了C++在打造基础通用的极大困难。表面上存在无穷无尽的选择,但是正确的路子,真心不多。一不小心,就面临无穷无尽的细节上的考究,最后造出来的轮子,反而引入更多的麻烦。而更糟糕的是,很多人更高估了自己对C++的认识,贸贸然就随随便便造轮子,还大规模的在代码上到处泛滥。
本页共64段,6208个字符,17216 Byte(字节)